package com.cq.hd.member.factory;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.*;
import com.cq.hd.member.api.dto.WithdrawalApplyDto;
import com.cq.hd.member.api.dto.WithdrawalApplyV2Dto;
import com.cq.hd.member.mapper.TbAgentBankUpdateRecordMapper;
import com.cq.hd.member.mq.provider.WithdrawalMsgProvider;
import com.cq.hd.member.po.*;
import com.cq.hd.member.service.TbAgentEnterApplyService;
import com.cq.hd.member.service.TbAppUserService;
import com.cq.hd.member.service.TbCommissionBillService;
import com.cq.hd.member.service.TbWithdrawalBillService;
import com.cq.hd.order.api.TbOrderSettleBillApi;
import com.cq.hd.order.api.dto.OrderSettleBillDto;
import com.cq.hd.order.api.vo.OrderSettleBillVo;
import com.cq.hd.system.api.vo.WithdrawalConfigVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

@Component
@Slf4j
public class AgentCommissionWithdrawalHandler extends AbstractWithdrawalHandler {

    @Autowired
    private TbAppUserService appUserService;

    @Autowired
    private TbWithdrawalBillService withdrawalBillService;

    @Autowired
    private TbAgentEnterApplyService agentEnterApplyService;

    @Autowired
    private TbCommissionBillService commissionBillService;

    @Autowired
    private TbAgentBankUpdateRecordMapper agentBankUpdateRecordMapper;

    @Autowired
    private TbOrderSettleBillApi orderSettleBillApi;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private WithdrawalMsgProvider withdrawalMsgProvider;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    protected Integer getType() {
        return WithdrawalTypeEnum.AGENT_COMMISSION.getValue();
    }

    @Override
    public Boolean apply(WithdrawalApplyDto withdrawalApplyDto, WithdrawalConfigVo withdrawalConfigVo) {
        // 如果是商户本金/商户补贴提现，就是商户id，如果是佣金提现，则是用户id
        Long userId = withdrawalApplyDto.getUserId();
        BigDecimal tradeAmt = withdrawalApplyDto.getTradeAmt();

        // 只要存在待审核的修改提现银行卡记录，则不能申请提现
        Integer waitAuditUpdateBankInfoCount = agentBankUpdateRecordMapper.selectCount(new QueryWrapper<TbAgentBankUpdateRecordPo>()
                .eq("del_state", 0)
                .eq("audit_state", AuditStateEnum.WAIT_AUDIT.getValue())
                .eq("user_id", userId));
        if (waitAuditUpdateBankInfoCount != null && waitAuditUpdateBankInfoCount > 0) {
            log.error("经纪人申请提现失败，存在待审核的修改银行卡记录，userId：{}", userId);
            Throw.isBusinessException("存在待审核的修改银行卡记录");
        }

        // 查询经纪人签约成功记录
        List<TbAgentEnterApplyPo> agentEnterApplyPos = agentEnterApplyService.list(new QueryWrapper<TbAgentEnterApplyPo>().eq("del_state", 0)
                .eq("user_id", userId).eq("state", AgentEnterStateEnum.SIGN_SUCCESS.getValue())
                .orderByDesc("apply_time"));
        if (CollectionUtils.isEmpty(agentEnterApplyPos)) {
            log.error("经纪人申请提现失败，未找到经纪人签约成功的记录，userId：{}", userId);
            Throw.isBusinessException("请先签约");
        }
        TbAgentEnterApplyPo tbAgentEnterApplyPo = agentEnterApplyPos.get(0);

        // 起提金额
        BigDecimal minAmt = withdrawalConfigVo.getMinAmt();
        // 单次最高可提金额
        BigDecimal singleMaxAmt = withdrawalConfigVo.getSingleMaxAmt();
        // 单日可提次数
        Integer dayCount = withdrawalConfigVo.getDayCount();
        // 提现自动审核方式(1-人工审核，2-自动审核)
        Integer autoApprovalType = withdrawalConfigVo.getAutoApprovalType();
        // 自动审核提现金额
        BigDecimal autoApprovalAmt = withdrawalConfigVo.getAutoApprovalAmt();

        // 今日提现次数已达上限
        if (tradeAmt.compareTo(minAmt) < 0) {
            Throw.isBusinessException("最少" + minAmt + "元起提");
        }

        // 最高可提xxx元
        if (tradeAmt.compareTo(singleMaxAmt) > 0) {
            Throw.isBusinessException("最高可提" + singleMaxAmt + "元");
        }

        LocalDateTime nowLocalDateTime = LocalDateUtil.getNowLocalDateTime();
        String yyyyMMdd = LocalDateUtil.toLocalDateToString(nowLocalDateTime.toLocalDate(), "yyyyMMdd");
        String reqSeqId = LocalDateUtil.toLocalDateTimeToString(nowLocalDateTime, "yyyyMMddHHmmss") + GenerateUtil.getRandomNum(5);

        // 今日提现次数已达上限
        String countStr = redisUtil.get(String.format(RedisKeyConstant.WITHDRAWAL_DAY_NUM_KEY, withdrawalApplyDto.getWithdrawalType(), yyyyMMdd, userId));
        if (!StringUtils.isBlank(countStr)) {
            int count = Integer.parseInt(countStr);
            if (count >= dayCount) {
                Throw.isBusinessException("今日提现次数已达上限");
            }
        }

        String hfId = tbAgentEnterApplyPo.getHfId();
        String acctId = "";
        String tokenNo = tbAgentEnterApplyPo.getTokenNo();
        String cardName = tbAgentEnterApplyPo.getCardName();
        String cardNo = tbAgentEnterApplyPo.getCardNo();

        if (StringUtils.isBlank(hfId) || StringUtils.isBlank(tokenNo) || StringUtils.isBlank(cardName) || StringUtils.isBlank(cardNo)) {
            log.error("经纪人申请提现失败，走自动提现时hf相关配置不能为空，userId：{}", userId);
            Throw.isBusinessException("请先签约");
        }

        // 需要对待支付/支付失败的结算资金做查单处理，如果存在待支付/支付失败的结算资金，则需要再次做余额支付税筹，如果转失败则修改状态
        OrderSettleBillDto orderSettleBillDto = new OrderSettleBillDto();
        orderSettleBillDto.setAgentId(userId);
        orderSettleBillDto.setTradeType(OrderSettleBillTradeTypeEnum.COMMISSION_AMT.getValue());
        orderSettleBillDto.setTradeStates(Arrays.asList(OrderSettleBillTradeStateEnum.WAIT.getValue(), OrderSettleBillTradeStateEnum.FAIL.getValue()));
        List<OrderSettleBillVo> orderSettleBillVos = orderSettleBillApi.listByDto(orderSettleBillDto).unpack();
        if (!CollectionUtils.isEmpty(orderSettleBillVos)) {
            for (OrderSettleBillVo orderSettleBillVo : orderSettleBillVos) {
                orderSettleBillApi.transactAmt(orderSettleBillVo);
            }
        }

        TbAppUserPo appUserPo = appUserService.getById(userId);
        if (appUserPo == null || appUserPo.getDelState() != 0) {
            Throw.isBusinessException("未找到用户数据");
        }
        BigDecimal commissionAmt = appUserPo.getCommissionAmt();

        if (tradeAmt.compareTo(commissionAmt) > 0) {
            Throw.isBusinessException("佣金余额不足");
        }

        // 计算提现服务费
        // 计算扣除手续费后的佣金      7.5%的手续费，不做四舍五入，去掉第三位
        BigDecimal calReceiveAmt = tradeAmt.divide(Constant.AGENT_AMT_RATE, 2, BigDecimal.ROUND_DOWN);
        BigDecimal feeAmt = tradeAmt.subtract(calReceiveAmt);

        TbWithdrawalBillPo tbWithdrawalBillPo = new TbWithdrawalBillPo();
        tbWithdrawalBillPo.setApplyNo(NoUtils.getWithdrawalBillNo());
        tbWithdrawalBillPo.setWithdrawalUserId(userId);
        tbWithdrawalBillPo.setBusinessId(0L);
        tbWithdrawalBillPo.setWithdrawalType(WithdrawalTypeEnum.AGENT_COMMISSION.getValue());
        tbWithdrawalBillPo.setCardName(cardName);
        tbWithdrawalBillPo.setCardNo(cardNo);
        tbWithdrawalBillPo.setBankName("");
        tbWithdrawalBillPo.setBeforeAmt(commissionAmt);
        tbWithdrawalBillPo.setTradeAmt(tradeAmt);
        tbWithdrawalBillPo.setAfterAmt(commissionAmt.subtract(tradeAmt));
        tbWithdrawalBillPo.setFeeAmt(feeAmt);
        tbWithdrawalBillPo.setReceiveAmt(calReceiveAmt);
        tbWithdrawalBillPo.setApplyTime(nowLocalDateTime);
        tbWithdrawalBillPo.setReqDate(yyyyMMdd);
        tbWithdrawalBillPo.setReqSeqId(reqSeqId);
        tbWithdrawalBillPo.setHfId(hfId);
        tbWithdrawalBillPo.setAcctId(acctId);
        tbWithdrawalBillPo.setTokenNo(tokenNo);
        tbWithdrawalBillPo.setCreateTime(nowLocalDateTime);
        tbWithdrawalBillPo.setUpdateTime(nowLocalDateTime);

        Long id = 0L;
        TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

        try {
            // 扣除经纪人佣金账户资金
            Boolean subCommissionAmtState = appUserService.subCommissionAmt(userId, tradeAmt);
            if (subCommissionAmtState == null || !subCommissionAmtState) {
                Throw.isBusinessException("账户佣金余额不足");
            }

            // 自动审核，判断申请提现金额是否小于等于自动审核提现金额
            if (autoApprovalType != null && autoApprovalType == 2
                    && autoApprovalAmt != null && autoApprovalAmt.compareTo(BigDecimal.ZERO) > 0
                    && tradeAmt.compareTo(autoApprovalAmt) <= 0) {
                // 走自动提现

                tbWithdrawalBillPo.setState(WithdrawalStateEnum.AUDIT_SUCCESS.getValue());
                boolean save = withdrawalBillService.save(tbWithdrawalBillPo);
                if (!save) {
                    Throw.isBusinessException("申请提现失败");
                }

                id = tbWithdrawalBillPo.getId();
            } else {
                // 走人工审核
                tbWithdrawalBillPo.setState(WithdrawalStateEnum.WAIT_AUDIT.getValue());
                boolean save = withdrawalBillService.save(tbWithdrawalBillPo);
                if (!save) {
                    Throw.isBusinessException("申请提现失败");
                }
            }

            // 增加佣金资金明细记录
            TbCommissionBillPo tbCommissionBillPo = new TbCommissionBillPo();
            tbCommissionBillPo.setBillNo(NoUtils.getCommissionBillNo());
            tbCommissionBillPo.setUserId(tbWithdrawalBillPo.getWithdrawalUserId());
            tbCommissionBillPo.setBillType(BillTypeEnum.EXPEND.getValue());
            tbCommissionBillPo.setTradeType(CommissionBillTradeTypeEnum.WITHDRAWAL_COMMISSION.getValue());
            tbCommissionBillPo.setRelationTradeNo(tbWithdrawalBillPo.getApplyNo());
            tbCommissionBillPo.setBeforeAmt(tbWithdrawalBillPo.getBeforeAmt());
            tbCommissionBillPo.setTradeAmt(tbWithdrawalBillPo.getTradeAmt());
            tbCommissionBillPo.setAfterAmt(tbWithdrawalBillPo.getAfterAmt());
            tbCommissionBillPo.setTradeTime(tbWithdrawalBillPo.getApplyTime());
            tbCommissionBillPo.setCreateTime(LocalDateTime.now());
            tbCommissionBillPo.setUpdateTime(LocalDateTime.now());
            boolean insert = commissionBillService.save(tbCommissionBillPo);
            if (!insert) {
                Throw.isBusinessException("添加佣金流水失败");
            }

            transactionManager.commit(transaction);
        } catch (Exception e) {
            //回滚事务
            transactionManager.rollback(transaction);
            log.error("<申请佣金提现>事务异常回滚", e);
            Throw.isBusinessException(e.getMessage());
        }

        if (id > 0) {
            // 发送mq消息做异步提现打款
            withdrawalMsgProvider.sendMsg(id);
        }

        // 增加提现次数
        redisUtil.incr(String.format(RedisKeyConstant.WITHDRAWAL_DAY_NUM_KEY, withdrawalApplyDto.getWithdrawalType(), yyyyMMdd, userId));

        return true;
    }

    @Override
    public Boolean applyV2(WithdrawalApplyV2Dto withdrawalApplyV2Dto, WithdrawalConfigVo withdrawalConfigVo) {
        return null;
    }

}
